package com.ruoyi.trackapply;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ExecUtil;
import com.ruoyi.common.utils.SceneUtil;
import com.ruoyi.common.utils.SseEmitterUtils;
import com.ruoyi.common.utils.ZipUtils;
import com.ruoyi.common.utils.biz.BizModule;
import com.ruoyi.common.utils.biz.PathUtil;
import com.ruoyi.common.utils.biz.ResultSaveModule;
import com.ruoyi.dm.component.manager.TrackDataManager;
import com.ruoyi.dm.domain.po.CollectTleRecordPO;
import com.ruoyi.dm.domain.po.SpaceTargetMeasurePO;
import com.ruoyi.dm.service.ICollectTleRecordService;
import com.ruoyi.dm.service.ISpaceTargetMeasureService;
import com.ruoyi.dm.service.ISpaceTrackCollectRecordService;
import com.ruoyi.system.domain.ResultSave;
import com.ruoyi.system.service.IResultSaveService;
import com.ruoyi.trackapply.component.OriginNameFilter;
import com.ruoyi.trackapply.domain.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 轨道定轨预报评估
 */
@Service
@Slf4j
public class OrbitForcastService {

    @Autowired
    PathUtil pathUtil;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TrackDataManager trackDataManager;

    @Autowired
    private ISpaceTrackCollectRecordService recordService;

    @Autowired
    private ICollectTleRecordService tleRecordService;

    private List<String> elements = ListUtil.of("X","Y","Z","VX","VY","VZ");

    @Autowired
    private ISpaceTargetMeasureService spaceTargetMeasureService;

    @Autowired
    private IResultSaveService resultSaveService;

    //tle数据预报
    public OrbitForcastVO tleCal(OrbitForcastParam param) throws Exception {
        //进度指示
        int percent = 1;
        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
        ForcastInputJsonBO forcastInputJsonBO = new ForcastInputJsonBO();
        ForcastInputJsonBO.InputBO inputBO = forcastInputJsonBO.new InputBO();
        forcastInputJsonBO.setInput(inputBO);
        inputBO.setTleFlag(true);
        inputBO.setIsGNSSpre(false);
        //拆分时间
        List<DateTime> deal = SceneUtil.deal(param.getScene());
        DateTime startTime =deal.get(0);
        DateTime endTime = deal.get(1);

        //步骤一  找tle轨道数据,并写入 tle.txt
        LambdaQueryWrapper<CollectTleRecordPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CollectTleRecordPO::getTleCode,param.getObjectCode());
        //预报时间5天前的数据 取最近的数据
         //年纪日 格式  24023
        DateTime startDays = DateUtil.offset(startTime,DateField.DAY_OF_MONTH, -5);
        queryWrapper.between(CollectTleRecordPO::getDataTime,startDays,startTime);
        queryWrapper.orderByDesc(CollectTleRecordPO::getDataTime);
        queryWrapper.last(" limit 1");
        CollectTleRecordPO collectTleRecordPO = tleRecordService.getOne(queryWrapper);
        if (null == collectTleRecordPO) {
            throw new ServiceException(startTime +"前5天内 没有TLE数据 可供参考");
        }
        String tmpGnnsTxt = PathUtil.tmpModuleDir(BizModule.TRACK_APPLY) + "/" + UUID.fastUUID() + ".txt";
        File tleFile = FileUtil.writeString(collectTleRecordPO.toString(), tmpGnnsTxt, "utf-8");
        inputBO.setTleFilePath(tleFile.getAbsolutePath());

        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");

        //组装预报时间
        ForcastInputJsonBO.StartTimeBO startBO = forcastInputJsonBO.new StartTimeBO();
        startBO.setBeginTime_Year(startTime.getField(DateField.YEAR));
        startBO.setBeginTime_Month(startTime.getField(DateField.MONTH)+1);
        startBO.setBeginTime_Day(startTime.getField(DateField.DAY_OF_MONTH));
        startBO.setBeginTime_Hour(startTime.getField(DateField.HOUR_OF_DAY));
        startBO.setBeginTime_Min(startTime.getField(DateField.MINUTE));
        startBO.setBeginTime_sec(Double.valueOf(startTime.getField(DateField.SECOND)));
        inputBO.setBeginTime(startBO);

        //预报结束时间
        ForcastInputJsonBO.EndTimeBO endBO = forcastInputJsonBO.new EndTimeBO();
        endBO.setEndTime_Year(endTime.getField(DateField.YEAR));
        endBO.setEndTime_Month(endTime.getField(DateField.MONTH)+1);
        endBO.setEndTime_Day(endTime.getField(DateField.DAY_OF_MONTH));
        endBO.setEndTime_Hour(endTime.getField(DateField.HOUR_OF_DAY));
        endBO.setEndTime_Min(endTime.getField(DateField.MINUTE));
        endBO.setEndTime_sec(Double.valueOf(endTime.getField(DateField.SECOND)));
        inputBO.setEndTime(endBO);
        //从数据库获取 查2个时间间隔  单位秒
        //int step = trackDataManager.queryStep(param.getSateName(), startTime, endTime);
        int step = 60;
        inputBO.setInterval(step);

        //一些配置
        ForcastInputJsonBO.ForcastConfBO confBO = forcastInputJsonBO.new ForcastConfBO();
        confBO.setDataPath("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/data/ADP/");
        confBO.setEphFilePath("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/data/ADP/JPLEPH.414");
        confBO.setStr("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/3rdparty/");
        forcastInputJsonBO.setConf(confBO);

        //输出
        ForcastInputJsonBO.ForcastOutputBO bo = forcastInputJsonBO.new ForcastOutputBO();
        String outPath = PathUtil.outputModuleDir(BizModule.TRACK_APPLY) + "/focast/";
        bo.setFilePath(outPath);
        FileUtil.mkdir(outPath);
        forcastInputJsonBO.setOutput(bo);


        //评估结果
        List<EstimateResVO> estimateList = new ArrayList<>();
        List<XbfVO> xbfList = new ArrayList<>(110);
        List<Date> timeList = null;
        //遍历 每个模型 ，并调用一次算法
        List<String> models = param.getModel();
        List<String> fiesResList = new ArrayList<>();
        for (String model : models) {
            //步骤二组装  ForcastInputJsonBO参数
            ForcastInputJsonBO.ForceModelParaBO forceModelParaBO = forcastInputJsonBO.new ForceModelParaBO();

            if (StringUtils.hasLength(param.getWindModel())) {
                switch (param.getWindModel()) {
                    case "HWM07":
                        forceModelParaBO.setWindFieldModel(1);
                        break;
                    case "HWCM":
                        forceModelParaBO.setWindFieldModel(2);
                        break;
                    default:
                        forceModelParaBO.setWindFieldModel(0);
                }
            }

            forceModelParaBO.setAtmDensityModel(checkModel(model));
            inputBO.setForceModelPara(forceModelParaBO);

            //步骤三  写入入参
            String satJson = com.alibaba.fastjson.JSONObject.toJSONString(forcastInputJsonBO, new OriginNameFilter());
            String prettyStr = JSONUtil.toJsonPrettyStr(satJson);
            String inoutJsonPath = PathUtil.tmpModuleDir(BizModule.TRACK_APPLY) + "/" + UUID.fastUUID() + ".json";
            FileUtil.writeString(prettyStr,inoutJsonPath,"utf-8");

            //步骤四  调用脚本
            //python /YB_all.py /InputOrbitPrediction.json /20240713060405orbitPredictData.txt
            String res = exec(inoutJsonPath, "###", param.getSseId());
            log.info("调用预报命令 res-{}",res);
            //Time        x        y        z        vx        vy        vz
            //2020-06-11T00:11:21.639    4656728.849314    -2000977.024185    -4627253.017900    4627.207159    -2211.782788    5631.285044
            //2020-06-11T00:12:21.639    4923315.103879    -2130353.278219    -4279346.225980    4255.827135    -2098.654269    5961.354918
            //2020-06-11T00:13:21.639    5167067.839393    -2252560.902419    -3912415.560515    3866.419628    -1972.812108    6265.171864
            String[] resSplit = res.split("[\r\n#]+");
            String outData = resSplit[1];
            fiesResList.add(outData);
            Object[] objArr= makeupXbfVO(outData, model);
            xbfList.add((XbfVO)objArr[0]);
            timeList = (List)objArr[1];
            //给算法缓冲时间
            SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
            Thread.sleep(1100);
        }
        //返回
        OrbitForcastBO orbitForcastBO = new OrbitForcastBO();
        orbitForcastBO.setTime(timeList);
        orbitForcastBO.setXbfUnit("test");
        orbitForcastBO.setResultList(xbfList);
        orbitForcastBO.setEstimate(estimateList);

        redisTemplate.opsForValue().set(MD5.create().digestHex(param.toString()),JSONUtil.toJsonStr(fiesResList),1, TimeUnit.HOURS);

        return dealWithReturn(orbitForcastBO);

    }

    //精密轨道数据预报
    public OrbitForcastVO gnnsCal(OrbitForcastParam param) throws Exception {
        //进度指示
        int percent = 1;
        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
        ForcastInputJsonBO forcastInputJsonBO = new ForcastInputJsonBO();
        ForcastInputJsonBO.InputBO inputBO = forcastInputJsonBO.new InputBO();
        forcastInputJsonBO.setInput(inputBO);
        inputBO.setTleFlag(false);
        inputBO.setIsGNSSpre(true);
        //拆分时间
        List<DateTime> deal = SceneUtil.deal(param.getScene());
        DateTime startTime =deal.get(0);
        DateTime endTime = deal.get(1);

        //步骤一  找轨道据,并写入 gnns.txt
        //List<CollectGnssPO> gnssPOS = trackDataManager.queryGnnsInMinute(param.getSateName(),startTime,endTime);
        List<CollectGnssPO> gnssPOS = trackDataManager.queryGnns(null,param.getSateName(),startTime,endTime);
        if (gnssPOS == null || gnssPOS.size() == 0) {
            throw new ServiceException(startTime+" 时间  GNSS无数据");
        }
        String tmpGnnsTxt = PathUtil.tmpModuleDir(BizModule.TRACK_APPLY) + "/" + UUID.fastUUID().toString(true) + ".txt";
        FileUtil.writeString("Time        x        y        z        vx        vy        vz",tmpGnnsTxt,"utf-8");
        File file = FileUtil.appendLines(gnssPOS, tmpGnnsTxt, "utf-8");
        //update@2024-10-25 修改,避免不同星数据格式不一致
        DateTime end = DateUtil.endOfDay(startTime);
        List<CollectGnssPO> examplePOS = trackDataManager.queryGnns(null, param.getSateName(),startTime,end);
        String exampleTxt = PathUtil.tmpModuleDir(BizModule.TRACK_APPLY) + "/" + UUID.fastUUID().toString(true) + ".txt";
        File orainFile = FileUtil.appendLines(examplePOS, exampleTxt, "utf-8");
        inputBO.setGnssFilePath(orainFile.getAbsolutePath());
        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");

        //组装预报时间
        Date forcastStart = gnssPOS.get(0).getObs_time();
        ForcastInputJsonBO.StartTimeBO startBO = forcastInputJsonBO.new StartTimeBO();
        startBO.setBeginTime_Year(DateUtil.year(forcastStart));
        startBO.setBeginTime_Month(DateUtil.month(forcastStart)+1);
        startBO.setBeginTime_Day(DateUtil.dayOfMonth(forcastStart));
        startBO.setBeginTime_Hour(DateUtil.hour(forcastStart,true));
        startBO.setBeginTime_Min(DateUtil.minute(forcastStart));
        startBO.setBeginTime_sec(Double.valueOf(DateUtil.second(forcastStart)));
        inputBO.setBeginTime(startBO);

        //预报结束时间
        Date forcastEnd = gnssPOS.get(gnssPOS.size()-1).getObs_time();
        ForcastInputJsonBO.EndTimeBO endBO = forcastInputJsonBO.new EndTimeBO();
        endBO.setEndTime_Year(DateUtil.year(forcastEnd));
        endBO.setEndTime_Month(DateUtil.month(forcastEnd)+1);
        endBO.setEndTime_Day(DateUtil.dayOfMonth(forcastEnd));
        endBO.setEndTime_Hour(DateUtil.hour(forcastEnd,true));
        endBO.setEndTime_Min(DateUtil.minute(forcastEnd));
        endBO.setEndTime_sec(Double.valueOf(DateUtil.second(forcastEnd)));
        inputBO.setEndTime(endBO);
        //从数据库获取 查2个时间间隔  单位秒
        int step = trackDataManager.queryStep(gnssPOS);
        inputBO.setInterval(step);

        //查询 目标信息，备用
        LambdaQueryWrapper<SpaceTargetMeasurePO> measureQw = new LambdaQueryWrapper<>();
        measureQw.select(SpaceTargetMeasurePO::getCode,SpaceTargetMeasurePO::getName,SpaceTargetMeasurePO::getDens,SpaceTargetMeasurePO::getWindArea,SpaceTargetMeasurePO::getFIndex,SpaceTargetMeasurePO::getLightIndex);
        measureQw.eq(SpaceTargetMeasurePO::getName,param.getSateName());
        SpaceTargetMeasurePO measure = spaceTargetMeasureService.getOne(measureQw);
        if (null == measure) {
            throw new ServiceException("未找到 "+param.getSateName()+" 的目标测量数据,请先去目标测量页面增加数据!");
        }

        //一些配置
        ForcastInputJsonBO.ForcastConfBO confBO = forcastInputJsonBO.new ForcastConfBO();
        confBO.setDataPath("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/data/ADP/");
        confBO.setEphFilePath("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/data/ADP/JPLEPH.414");
        confBO.setStr("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/3rdparty/");
        forcastInputJsonBO.setConf(confBO);

        //输出
        ForcastInputJsonBO.ForcastOutputBO bo = forcastInputJsonBO.new ForcastOutputBO();
        String outPath = PathUtil.outputModuleDir(BizModule.TRACK_APPLY) + "/focast/";
        bo.setFilePath(outPath);
        FileUtil.mkdir(outPath);
        forcastInputJsonBO.setOutput(bo);


        //评估结果
        List<EstimateResVO> estimateList = new ArrayList<>();
        List<XbfVO> resList = new ArrayList<>();
        List<XbfVO> errorList = new ArrayList<>();
        List<Date> timeList = null;
        //遍历 每个模型 ，并调用一次算法
        List<String> models = param.getModel();
        List<String> dataList = new ArrayList<>();
        SseEmitterUtils.sendMessage(param.getSseId(),"20");
        for (String model : models) {
            //步骤二组装  ForcastInputJsonBO参数
            ForcastInputJsonBO.ForceModelParaBO forceModelParaBO = forcastInputJsonBO.new ForceModelParaBO();


            if (StringUtils.hasLength(param.getWindModel())) {
                switch (param.getWindModel()) {
                    case "HWM07":
                        forceModelParaBO.setWindFieldModel(1);
                        break;
                    case "HWCM":
                        forceModelParaBO.setWindFieldModel(2);
                        break;
                    default:
                        forceModelParaBO.setWindFieldModel(0);
                }
            }

            forceModelParaBO.setDragCd(Double.valueOf(measure.getFIndex()));
            forceModelParaBO.setDragArea(Double.valueOf(measure.getWindArea()));
            forceModelParaBO.setDragMass(Double.valueOf(measure.getDens()));
            forceModelParaBO.setCr(Double.valueOf(measure.getLightIndex()));
            forceModelParaBO.setAtmDensityModel(checkModel(model));
            inputBO.setForceModelPara(forceModelParaBO);

            //步骤三  写入入参
            String satJson = com.alibaba.fastjson.JSONObject.toJSONString(forcastInputJsonBO, new OriginNameFilter());
            String prettyStr = JSONUtil.toJsonPrettyStr(satJson);
            String inoutJsonPath = PathUtil.tmpModuleDir(BizModule.TRACK_APPLY) + "/" + UUID.fastUUID() + ".json";
            FileUtil.writeString(prettyStr,inoutJsonPath,"utf-8");

            //步骤四  调用脚本
            String res = exec(inoutJsonPath,file.getAbsolutePath(),param.getSseId());
            log.info("调用预报命令 res-{}",res);
            //          ###
            //      /dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/outPut/20240717082025orbitPredictData.txt
            //      /dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/outPut/test.txt
            //          ###
            //   {'X_MSE': 0.0, 'Y_MSE': 0.0, 'Z_MSE': 0.0, 'VX_MSE': 0.0, 'VY_MSE': 0.0, 'VZ_MSE': 0.0}
            //   {'X_MAE': 0.0, 'Y_MAE': 0.0, 'Z_MAE': 0.0, 'VX_MAE': 0.0, 'VY_MAE': 0.0, 'VZ_MAE': 0.0}
            //   {'X_RMSE': 0.0, 'Y_RMSE': 0.0, 'Z_RMSE': 0.0, 'VX_RMSE': 0.0, 'VY_RMSE': 0.0, 'VZ_RMSE': 0.0}
            String[] resSplit = res.split("[\r\n#]+");
            String outData = resSplit[1];
            String outRes = resSplit[2];
            String mse = resSplit[3];
            String mae = resSplit[4];
            String rmse = resSplit[5];
            //组装  误差返回
            Object[] objOutRes= makeupXbfVO(outRes, model);
            XbfVO outRe = (XbfVO) objOutRes[0];
            errorList.add(outRe);
            //组装 评估结果
            JSONObject mseObj = JSONUtil.parseObj(mse);
            JSONObject maeObj = JSONUtil.parseObj(mae);
            JSONObject rmseObj = JSONUtil.parseObj(rmse);
            for (String element : elements) {
                EstimateResVO build = EstimateResVO.builder()
                        .mae(new BigDecimal(maeObj.getStr(element+"_MAE")))
                        .mse(new BigDecimal(mseObj.getStr(element+"_MSE")))
                        .rmse(new BigDecimal(rmseObj.getStr(element+"_RMSE")))
                        .model(model).param(element).build();
                estimateList.add(build);
            }

            //结果
            Object[] objArr= makeupXbfVO(outData, model);
            resList.add((XbfVO)objArr[0]);
            timeList = (List)objArr[1];
            dataList.add(res);
            //给算法缓冲时间
            SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
            Thread.sleep(1100);
        }
        //返回
        OrbitForcastBO orbitForcastBO = new OrbitForcastBO();
        orbitForcastBO.setTime(timeList);
        orbitForcastBO.setXbfUnit("test");
        orbitForcastBO.setResultList(resList);
        orbitForcastBO.setErrorList(errorList);
        orbitForcastBO.setEstimate(estimateList);
        redisTemplate.opsForValue().set(MD5.create().digestHex(param.toString()),JSONUtil.toJsonStr(dataList),1, TimeUnit.HOURS);
        file.delete();
        return dealWithReturn(orbitForcastBO);

    }

    /**
     * 通过模型 映射 数字

     * @param model
     * @return
     */
    private int checkModel(String model) {
        switch (model) {
            case "HADCAM":return 1;
            case "HALAM":return 2;
            case "NRLMSISE-00":return 3;
            case "Jacchia71":return 4;
            case "JB2008":return 5;
            case "DTM2020":return 6;
            default: throw new ServiceException("无效的模型名称");
        }
    }


    //页面 返回特定的格式
    private OrbitForcastVO dealWithReturn(OrbitForcastBO bo) {
        OrbitForcastVO resVO = new OrbitForcastVO();
        resVO.setTime(bo.getTime());
        resVO.setEstimate(bo.getEstimate());
        if (null != bo.getErrorList()) {
            //有误差
            Map<String, Object> ocxyz = new HashMap<>();
            for (XbfVO vo : bo.getErrorList()) {
                String model = vo.getModel();
                ocxyz.put(model + "_X", vo.getX());
                ocxyz.put(model + "_Y", vo.getY());
                ocxyz.put(model + "_Z", vo.getZ());
            }
            resVO.setErrorXyz(ocxyz);
            Map<String, Object> ocv = new HashMap<>();
            for (XbfVO vo : bo.getErrorList()) {
                String model = vo.getModel();
                ocv.put(model+"_VX",vo.getVx());
                ocv.put(model+"_VY",vo.getVy());
                ocv.put(model+"_VZ",vo.getVz());
            }
            resVO.setErrorV(ocv);
        }
        Map<String, Object> resxyz = new HashMap<>();
        for (XbfVO vo : bo.getResultList()) {
            String model = vo.getModel();
            resxyz.put(model+"_X",vo.getX());
            resxyz.put(model+"_Y",vo.getY());
            resxyz.put(model+"_Z",vo.getZ());
        }
        resVO.setResXyz(resxyz);
        Map<String, Object> resV = new HashMap<>();
        for (XbfVO vo : bo.getResultList()) {
            String model = vo.getModel();
            resV.put(model+"_VX",vo.getVx());
            resV.put(model+"_VY",vo.getVy());
            resV.put(model+"_VZ",vo.getVz());
        }
        resVO.setResV(resV);
        return resVO;
    }

    public void save(OrbitForcastParam param) {
        List<String> dataList = resByParam(param);
        param.setSseId(null);
        List<DateTime> times = SceneUtil.deal(param.getScene());
        DateTime obsStart = times.get(0);
        DateTime obsEnd = times.get(1);
        ResultSave entity = ResultSave.builder()
                .params("")
                .module(ResultSaveModule.TRACK_APPLY)
                .submodule(ResultSaveModule.TRACK_APPLY_FORCAST)
                .resultData(JSONUtil.toJsonStr(dataList))
                .startTime(DateUtil.format(obsStart,"yyyy-MM-dd"))
                .endTime(DateUtil.format(obsEnd,"yyyy-MM-dd"))
                .createTime(new Date())
                .build();
        resultSaveService.resultSave(param,entity);
    }

    /**
     * 通过参数 查询结果缓存
     * @param param
     * @return
     */
    private List<String> resByParam(OrbitForcastParam param) {
        String cachRes = (String)redisTemplate.opsForValue().get(MD5.create().digestHex(param.toString()));
        if (!StringUtils.hasLength(cachRes)) {
            throw new ServiceException("请先计算后再保存");
        }
        List<String> dataList = new ArrayList<>();

        JSONArray catArray = JSONUtil.parseArray(cachRes);
        if ("track".equals(param.getFocastType())) {
            for (Object o : catArray) {
                String str= (String) o;
                //          ###
                //      /dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/outPut/20240717082025orbitPredictData.txt
                //      /dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/outPut/test.txt
                //          ###
                //   {'X_MSE': 0.0, 'Y_MSE': 0.0, 'Z_MSE': 0.0, 'VX_MSE': 0.0, 'VY_MSE': 0.0, 'VZ_MSE': 0.0}
                //   {'X_MAE': 0.0, 'Y_MAE': 0.0, 'Z_MAE': 0.0, 'VX_MAE': 0.0, 'VY_MAE': 0.0, 'VZ_MAE': 0.0}
                //   {'X_RMSE': 0.0, 'Y_RMSE': 0.0, 'Z_RMSE': 0.0, 'VX_RMSE': 0.0, 'VY_RMSE': 0.0, 'VZ_RMSE': 0.0}
                String[] resSplit = str.split("[\r\n#]+");
                String outData = resSplit[1];
                String outRes = resSplit[2];
                String mse = resSplit[3];
                String mae = resSplit[4];
                String rmse = resSplit[5];
                String replace = outData.replace(".txt", ".json").replace(".TXT", ".json");
                FileUtil.writeString(JSONUtil.toJsonStr(ListUtil.of(mse,mae,rmse)),replace,"utf-8");
                dataList.add(outData);
                dataList.add(outRes);
                dataList.add(replace);
            }
        }else if ("tle".equals(param.getFocastType())) {
            for (Object o : catArray) {
                String str= (String) o;
                dataList.add(str);
            }
        }

        return dataList;
    }

    public File download(OrbitForcastParam param) throws IOException {
        List<String> dataList = resByParam(param);
        String timeStr = DateUtil.format(new Date(), "yyyyMMddHHmmss");
        String zipPath = RuoYiConfig.getDownloadPath() + "/预报效应评估-"+timeStr+".zip";
        ZipUtils.zipWithPath(dataList,zipPath);
        return new File(zipPath);
    }



    /**
     * 组装XbfVO返回值
     *
     * @param filePath 文件路径
     * @param model
     * @return
     * @throws Exception
     */
    private Object[] makeupXbfVO(String filePath, String model) throws Exception {
        //获取行数
        File file = new File(filePath);
        long lines = Files.lines(Paths.get(file.getPath())).count();
        //页面展示1000条数据
        int num = 1000;
        int skip = 1;
        if (lines > 1000) {
            skip = (int) (lines / num);
        }
        List<Date> timeList = new ArrayList<>(110);
        List<BigDecimal> xList = new ArrayList<>(110);
        List<BigDecimal> yList = new ArrayList<>(110);
        List<BigDecimal> zList = new ArrayList<>(110);
        List<BigDecimal> vxList = new ArrayList<>(110);
        List<BigDecimal> vyList = new ArrayList<>(110);
        List<BigDecimal> vzList = new ArrayList<>(110);
        BufferedReader reader = new BufferedReader(new FileReader(file));
        //忽略首行
        reader.readLine();
        int lineNum = 0;
        String line = "";
        while (null != (line = reader.readLine())) {
            // 2024-02-23T04:00:00.000000    2667886.511   41818236.802   -4571189.757     -13.473094     -26.308005    -223.755214
            if (lineNum % skip == 0) {
                String[] spp = line.split("[\\s,]+");
                timeList.add(DateUtil.parse(spp[0], DateTimeFormatter.ISO_DATE_TIME));
                xList.add(new BigDecimal(spp[1]).setScale(3,BigDecimal.ROUND_HALF_UP));
                yList.add(new BigDecimal(spp[2]).setScale(3,BigDecimal.ROUND_HALF_UP));
                zList.add(new BigDecimal(spp[3]).setScale(3,BigDecimal.ROUND_HALF_UP));
                vxList.add(new BigDecimal(spp[4]).setScale(8,BigDecimal.ROUND_HALF_UP));
                vyList.add(new BigDecimal(spp[5]).setScale(8,BigDecimal.ROUND_HALF_UP));
                vzList.add(new BigDecimal(spp[6]).setScale(8,BigDecimal.ROUND_HALF_UP));
            }
            lineNum++;
        }

        XbfVO vo = new XbfVO();
        vo.setModel(model);
        vo.setX(xList);
        vo.setY(yList);
        vo.setZ(zList);
        vo.setVx(vxList);
        vo.setVy(vyList);
        vo.setVz(vzList);
        return new Object[]{vo,timeList};
    }

    public OrbitForcastVO cal(OrbitForcastParam param) throws Exception {
        if ("track".equals(param.getFocastType())) {
            String sateName = param.getSateName();
            if (com.ruoyi.common.utils.StringUtils.isEmpty(sateName)){
                throw new ServiceException("精密轨道-卫星不能为空");
            }
            return gnnsCal(param);
        }else if ("tle".equals(param.getFocastType())) {
            String objectCode = param.getObjectCode();
            if (com.ruoyi.common.utils.StringUtils.isEmpty(objectCode)){
                throw new ServiceException("tle-目标编号不能为空");
            }
            return tleCal(param);
        }
        throw new ServiceException("该类型暂不支持");
    }

    private String exec(String jsonPath, String dataPath, String sseId) throws Exception {
        String script = PathUtil.codeModuleDir(BizModule.TASK_ASSESS) + PathUtil.moduleDirs().getTaskAssess().get("forcast");
        //String commond = String.format("sh %s %s '%s' '%s'",script, jsonPath, dataPath,jsonPath.replace(".json",".txt"));
        String commond = String.format("cd /dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/bin && python %s %s '%s' '%s'", script, jsonPath, dataPath,jsonPath.replace(".json",".txt"));
        log.info("执行命令:{}",commond);
        List<String> resLines = ExecUtil.execPythonZw(Stream.of("bash", "-c", commond).collect(Collectors.toList()), sseId);
        String res = CollectionUtil.join(resLines,"\n");
        return res;
        //Process exec = Runtime.getRuntime().exec(commond);
        //InputStream inputStream = exec.getInputStream();
        //BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        //exec.waitFor();
        //String s = "";
        //StringBuffer buffer = new StringBuffer();
        //while (null != (s=reader.readLine())) {
        //    buffer.append(s);
        //    buffer.append("\n");
        //}
        //return buffer.toString();
    }
}
